﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Data.SqlClient;

namespace SPTraceView.Model
{
    internal class TraceToDb
    {

        private Queue<TraceEvent> events = new Queue<TraceEvent>();

        private object m_SyncRoot = new object();
        private bool m_Running = false;
        private Thread m_ServerThread = null;

        private SqlConnection connection = null;
        



        public void TraceEvent(
            string serverName,
            ULS.TraceSeverity severity,
            long timeStamp,
            uint processId,
            string exeName,
            string product,
            string category,
            string message,
            Int64 timeCorrection)
        {

            lock (m_SyncRoot)
            {
                var ev = new TraceEvent()
                {
                    ServerName = serverName,
                    Severity = severity,
                    TimeStamp = timeStamp,
                    ProcessId = processId,
                    ExeName = exeName,
                    Product = product,
                    Category = category,
                    Message = message,
                    timeCorrection = timeCorrection
                };
                events.Enqueue(ev);
            }
        }

        public void Start(string connectionString)
        {
            lock (m_SyncRoot)
            {
                lock(this)
                {
                connection = new SqlConnection(connectionString);
                connection.Open();

                Trace.WriteLine(string.Format("Starting up a thread to send events", "SPTraceView"));

                m_ServerThread = new Thread(new ThreadStart(SendToDbServerWorker));
                m_ServerThread.SetApartmentState(ApartmentState.STA);
                m_Running = true;
                m_ServerThread.Start();
                }
            }
        }

        public void Close()
        {
            if (m_ServerThread != null)
            {
                Trace.WriteLine("Shutting down the thread to send events", "SPTraceView");
                lock(this)
                {
                if (m_Running)
                    connection.Close();
                
                m_Running = false;
                }
                
                

                if (m_ServerThread.IsAlive)
                {
                    m_ServerThread.Abort();
                    m_ServerThread.Join(30000);
                }
                m_ServerThread = null;
            }
        }

        private void SendToDbServerWorker()
        {
            while (m_Running)
            {
                if (events.Count > 0)
                {

                    if (connection.State != System.Data.ConnectionState.Open)
                        connection.Open();

                    TraceEvent ev;
                    lock (m_SyncRoot)
                    {
                        ev = events.Dequeue();
                    }

                    lock(this)
                    {
                    //TODO: using a connection to Db send this to the database
                    SqlCommand cmd = new SqlCommand("AddULSEvent", connection);
                    cmd.Parameters.AddWithValue("ServerName", ev.ServerName);
                    cmd.Parameters.AddWithValue("Severity", ev.Severity.ToString());
                    cmd.Parameters.AddWithValue("TimeStamp",DateTime.FromFileTime(ev.TimeStamp));
                    cmd.Parameters.AddWithValue("ProcessId", (int)ev.ProcessId);
                    cmd.Parameters.AddWithValue("Product", ev.Product);
                    cmd.Parameters.AddWithValue("Category", ev.Category);
                    cmd.Parameters.AddWithValue("Message",ev.Message);
                    cmd.Parameters.AddWithValue("TimeCorrection",ev.timeCorrection);

                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                    cmd.ExecuteNonQuery();
                    }
                }
                else
                    Thread.Sleep(250);

            }

        }

    }
}
